"""K8s提取器文件操作工具模块"""

import os
import shutil
import glob
from typing import List, Dict, Any, Optional, Tuple, Set
import logging
import datetime
import hashlib

logger = logging.getLogger(__name__)

def ensure_dir(directory: str) -> bool:
    """
    确保目录存在，如果不存在则创建
    
    Args:
        directory: 目录路径
        
    Returns:
        是否成功创建或目录已存在
    """
    if not os.path.exists(directory):
        try:
            os.makedirs(directory, exist_ok=True)
            logger.debug(f"创建目录: {directory}")
            return True
        except Exception as e:
            logger.error(f"创建目录失败: {directory}, 错误: {str(e)}")
            return False
    return True

def clean_directory(directory: str) -> bool:
    """
    清空目录内容但保留目录
    
    Args:
        directory: 要清空的目录路径
        
    Returns:
        是否成功清空
    """
    if not os.path.exists(directory):
        logger.debug(f"目录不存在，无需清空: {directory}")
        return True
    
    try:
        for item in os.listdir(directory):
            item_path = os.path.join(directory, item)
            if os.path.isdir(item_path):
                shutil.rmtree(item_path)
            else:
                os.remove(item_path)
        logger.debug(f"目录已清空: {directory}")
        return True
    except Exception as e:
        logger.error(f"清空目录失败: {directory}, 错误: {str(e)}")
        return False

def remove_directory(directory: str) -> bool:
    """
    完全删除目录
    
    Args:
        directory: 要删除的目录路径
        
    Returns:
        是否成功删除
    """
    if not os.path.exists(directory):
        logger.debug(f"目录不存在，无需删除: {directory}")
        return True
    
    try:
        shutil.rmtree(directory)
        logger.debug(f"目录已删除: {directory}")
        return True
    except Exception as e:
        logger.error(f"删除目录失败: {directory}, 错误: {str(e)}")
        return False

def get_absolute_path(path: str) -> str:
    """
    获取绝对路径
    
    Args:
        path: 输入路径
        
    Returns:
        绝对路径
    """
    return os.path.abspath(path)

def get_relative_path(path: str, base_path: str) -> str:
    """
    获取相对路径
    
    Args:
        path: 完整路径
        base_path: 基准路径
        
    Returns:
        相对于base_path的相对路径
    """
    try:
        return os.path.relpath(path, base_path)
    except ValueError as e:
        logger.error(f"获取相对路径失败: {str(e)}")
        return os.path.basename(path)

def normalize_path(path: str) -> str:
    """
    规范化路径（处理斜杠方向、相对路径等）
    
    Args:
        path: 输入路径
        
    Returns:
        规范化后的路径
    """
    return os.path.normpath(path)

def join_paths(*paths: str) -> str:
    """
    拼接路径
    
    Args:
        paths: 路径片段
        
    Returns:
        拼接后的路径
    """
    return os.path.join(*paths)

def split_path(path: str) -> Tuple[str, str]:
    """
    分割路径为目录和文件名
    
    Args:
        path: 输入路径
        
    Returns:
        (目录, 文件名) 元组
    """
    return os.path.split(path)

def get_filename(path: str) -> str:
    """
    获取路径中的文件名部分（带扩展名）
    
    Args:
        path: 输入路径
        
    Returns:
        文件名（带扩展名）
    """
    return os.path.basename(path)

def get_file_stem(path: str) -> str:
    """
    获取路径中的文件名（不带扩展名）
    
    Args:
        path: 输入路径
        
    Returns:
        文件名（不带扩展名）
    """
    return os.path.splitext(os.path.basename(path))[0]

def get_extension(path: str) -> str:
    """
    获取文件扩展名（包含点号）
    
    Args:
        path: 输入路径
        
    Returns:
        文件扩展名
    """
    return os.path.splitext(path)[1]

def find_files(directory: str, extensions: Optional[List[str]] = None, recursive: bool = True) -> List[str]:
    """
    查找指定目录下所有符合扩展名的文件
    
    Args:
        directory: 要查找的目录
        extensions: 文件扩展名列表，如['.yaml', '.yml']
        recursive: 是否递归查找子目录
        
    Returns:
        找到的文件路径列表
    """
    if extensions is None:
        extensions = ['.yaml', '.yml', '.json']
        
    files = []
    
    # 确保扩展名都以.开头
    normalized_extensions = [
        ext if ext.startswith('.') else f'.{ext}' for ext in extensions
    ]
    
    if not os.path.isdir(directory):
        logger.error(f"目录不存在: {directory}")
        return files
    
    for root, _, filenames in os.walk(directory):
        for filename in filenames:
            _, ext = os.path.splitext(filename)
            if ext.lower() in normalized_extensions:
                files.append(os.path.join(root, filename))
        if not recursive:
            break
            
    logger.debug(f"在{directory}中找到{len(files)}个文件")
    return files

def find_files_by_pattern(directory: str, pattern: str, recursive: bool = True) -> List[str]:
    """
    使用glob模式查找文件
    
    Args:
        directory: 要查找的目录
        pattern: glob模式，如"*.txt"
        recursive: 是否递归查找子目录
        
    Returns:
        找到的文件路径列表
    """
    if recursive:
        search_pattern = os.path.join(directory, "**", pattern)
        return glob.glob(search_pattern, recursive=True)
    else:
        search_pattern = os.path.join(directory, pattern)
        return glob.glob(search_pattern)

def copy_file(src: str, dst: str, overwrite: bool = True) -> bool:
    """
    复制文件
    
    Args:
        src: 源文件路径
        dst: 目标文件路径
        overwrite: 是否覆盖已存在的目标文件
        
    Returns:
        是否成功复制
    """
    if not os.path.exists(src):
        logger.error(f"源文件不存在: {src}")
        return False
        
    if os.path.exists(dst) and not overwrite:
        logger.debug(f"目标文件已存在，不覆盖: {dst}")
        return True
        
    try:
        # 确保目标目录存在
        dst_dir = os.path.dirname(dst)
        ensure_dir(dst_dir)
        
        shutil.copy2(src, dst)
        logger.debug(f"文件已复制: {src} -> {dst}")
        return True
    except Exception as e:
        logger.error(f"复制文件失败: {src} -> {dst}, 错误: {str(e)}")
        return False

def move_file(src: str, dst: str, overwrite: bool = True) -> bool:
    """
    移动文件
    
    Args:
        src: 源文件路径
        dst: 目标文件路径
        overwrite: 是否覆盖已存在的目标文件
        
    Returns:
        是否成功移动
    """
    if not os.path.exists(src):
        logger.error(f"源文件不存在: {src}")
        return False
        
    if os.path.exists(dst):
        if not overwrite:
            logger.debug(f"目标文件已存在，不覆盖: {dst}")
            return True
        try:
            os.remove(dst)
        except Exception as e:
            logger.error(f"删除已存在目标文件失败: {dst}, 错误: {str(e)}")
            return False
        
    try:
        # 确保目标目录存在
        dst_dir = os.path.dirname(dst)
        ensure_dir(dst_dir)
        
        shutil.move(src, dst)
        logger.debug(f"文件已移动: {src} -> {dst}")
        return True
    except Exception as e:
        logger.error(f"移动文件失败: {src} -> {dst}, 错误: {str(e)}")
        return False

def remove_file(path: str) -> bool:
    """
    删除文件
    
    Args:
        path: 要删除的文件路径
        
    Returns:
        是否成功删除
    """
    if not os.path.exists(path):
        logger.debug(f"文件不存在，无需删除: {path}")
        return True
        
    try:
        os.remove(path)
        logger.debug(f"文件已删除: {path}")
        return True
    except Exception as e:
        logger.error(f"删除文件失败: {path}, 错误: {str(e)}")
        return False

def read_file(path: str, encoding: str = 'utf-8') -> Optional[str]:
    """
    读取文件内容
    
    Args:
        path: 文件路径
        encoding: 文件编码
        
    Returns:
        文件内容，如果读取失败则返回None
    """
    if not os.path.exists(path):
        logger.error(f"文件不存在: {path}")
        return None
        
    try:
        with open(path, 'r', encoding=encoding) as f:
            content = f.read()
        logger.debug(f"已读取文件: {path}")
        return content
    except Exception as e:
        logger.error(f"读取文件失败: {path}, 错误: {str(e)}")
        return None

def write_file(path: str, content: str, encoding: str = 'utf-8') -> bool:
    """
    写入文件内容
    
    Args:
        path: 文件路径
        content: 要写入的内容
        encoding: 文件编码
        
    Returns:
        是否成功写入
    """
    try:
        # 确保目标目录存在
        dst_dir = os.path.dirname(path)
        ensure_dir(dst_dir)
        
        with open(path, 'w', encoding=encoding) as f:
            f.write(content)
        logger.debug(f"已写入文件: {path}")
        return True
    except Exception as e:
        logger.error(f"写入文件失败: {path}, 错误: {str(e)}")
        return False

def append_file(path: str, content: str, encoding: str = 'utf-8') -> bool:
    """
    追加内容到文件
    
    Args:
        path: 文件路径
        content: 要追加的内容
        encoding: 文件编码
        
    Returns:
        是否成功追加
    """
    try:
        # 确保目标目录存在
        dst_dir = os.path.dirname(path)
        ensure_dir(dst_dir)
        
        with open(path, 'a', encoding=encoding) as f:
            f.write(content)
        logger.debug(f"已追加内容到文件: {path}")
        return True
    except Exception as e:
        logger.error(f"追加内容到文件失败: {path}, 错误: {str(e)}")
        return False

def get_file_size(path: str) -> int:
    """
    获取文件大小（字节数）
    
    Args:
        path: 文件路径
        
    Returns:
        文件大小，如果文件不存在则返回0
    """
    if not os.path.exists(path) or not os.path.isfile(path):
        return 0
    return os.path.getsize(path)

def get_file_modification_time(path: str) -> Optional[datetime.datetime]:
    """
    获取文件最后修改时间
    
    Args:
        path: 文件路径
        
    Returns:
        修改时间，如果文件不存在则返回None
    """
    if not os.path.exists(path):
        return None
    
    mtime = os.path.getmtime(path)
    return datetime.datetime.fromtimestamp(mtime)

def get_file_hash(path: str, hash_type: str = 'md5') -> Optional[str]:
    """
    计算文件哈希值
    
    Args:
        path: 文件路径
        hash_type: 哈希算法类型，支持'md5'、'sha1'、'sha256'
        
    Returns:
        文件哈希值，如果计算失败则返回None
    """
    if not os.path.exists(path):
        logger.error(f"文件不存在: {path}")
        return None
    
    hash_types = {
        'md5': hashlib.md5,
        'sha1': hashlib.sha1,
        'sha256': hashlib.sha256
    }
    
    if hash_type not in hash_types:
        logger.error(f"不支持的哈希类型: {hash_type}")
        return None
    
    try:
        hash_obj = hash_types[hash_type]()
        with open(path, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), b''):
                hash_obj.update(chunk)
        return hash_obj.hexdigest()
    except Exception as e:
        logger.error(f"计算文件哈希值失败: {path}, 错误: {str(e)}")
        return None

def create_directory_structure(base_path: str, structure: Dict[str, Any]) -> bool:
    """
    根据给定的结构创建目录树
    
    Args:
        base_path: 基础路径
        structure: 目录结构字典，如 {"dir1": {}, "dir2": {"subdir1": {}}}
        
    Returns:
        是否成功创建
    """
    try:
        for name, sub_structure in structure.items():
            path = os.path.join(base_path, name)
            if isinstance(sub_structure, dict):
                # 这是一个子目录
                ensure_dir(path)
                create_directory_structure(path, sub_structure)
            else:
                # 这是一个文件
                content = "" if sub_structure is None else str(sub_structure)
                write_file(path, content)
        return True
    except Exception as e:
        logger.error(f"创建目录结构失败: {base_path}, 错误: {str(e)}")
        return False

def mirror_directory_structure(src_dir: str, dst_dir: str, copy_files: bool = False) -> bool:
    """
    镜像源目录结构到目标目录
    
    Args:
        src_dir: 源目录
        dst_dir: 目标目录
        copy_files: 是否复制文件，False只创建目录结构
        
    Returns:
        是否成功镜像
    """
    if not os.path.exists(src_dir) or not os.path.isdir(src_dir):
        logger.error(f"源目录不存在: {src_dir}")
        return False
    
    try:
        # 创建目标目录
        ensure_dir(dst_dir)
        
        # 遍历源目录
        for root, dirs, files in os.walk(src_dir):
            # 计算相对路径
            rel_path = os.path.relpath(root, src_dir)
            
            # 在目标目录创建子目录
            for dir_name in dirs:
                target_dir = os.path.join(dst_dir, rel_path, dir_name)
                ensure_dir(target_dir)
            
            # 如果需要复制文件
            if copy_files:
                for file_name in files:
                    source_file = os.path.join(root, file_name)
                    target_file = os.path.join(dst_dir, rel_path, file_name)
                    copy_file(source_file, target_file)
        
        return True
    except Exception as e:
        logger.error(f"镜像目录结构失败: {src_dir} -> {dst_dir}, 错误: {str(e)}")
        return False

def find_k8s_files(directory: str, recursive: bool = True) -> Dict[str, List[str]]:
    """
    查找目录下的K8s相关文件，并按类型分类
    
    Args:
        directory: 要查找的目录
        recursive: 是否递归查找子目录
        
    Returns:
        按扩展名分类的文件列表字典
    """
    if not os.path.exists(directory) or not os.path.isdir(directory):
        logger.error(f"目录不存在: {directory}")
        return {}
    
    result = {
        'yaml': [],
        'json': [],
        'other': []
    }
    
    # 查找文件
    yaml_files = find_files(directory, ['.yaml', '.yml'], recursive)
    json_files = find_files(directory, ['.json'], recursive)
    
    result['yaml'] = yaml_files
    result['json'] = json_files
    
    logger.info(f"在{directory}中找到{len(yaml_files)}个YAML文件和{len(json_files)}个JSON文件")
    return result